﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.IO.Compression;
using System.Web.Caching;
using System.ServiceModel.Syndication;
using System.Collections;

namespace dasBlog.Storage
{
    public static class CacheUtil
    {
        public static XmlDictionaryReader AddReader(this Cache cache, string key, XmlReader reader)
        {
            return AddReader(cache, key, reader, null, TimeSpan.FromMinutes(60), CacheItemPriority.Normal);
        }

        public static XmlDictionaryReader AddReader(this Cache cache, string key, XmlReader reader, CacheItemPriority priority)
        {
            return AddReader(cache, key, reader, null, TimeSpan.FromMinutes(60), priority);
        }

        public static XmlDictionaryReader AddReader(this Cache cache, string key, XmlReader reader, string dependencyKey)
        {
            return AddReader(cache, key, reader, dependencyKey, TimeSpan.FromMinutes(60), CacheItemPriority.Normal);
        }

        public static XmlDictionaryReader AddReader(this Cache cache, string key, XmlReader reader, string dependencyKey, CacheItemPriority priority)
        {
            return AddReader(cache, key, reader, dependencyKey, TimeSpan.FromMinutes(60), priority);
        }

        public static XmlDictionaryReader AddReader(this Cache cache, string key, XmlReader reader, string dependencyKey, TimeSpan slidingExpiration, CacheItemPriority priority)
        {
            MemoryStream buffer = new MemoryStream();
            //DeflateStream compression = new DeflateStream(buffer, CompressionMode.Compress);
            XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(buffer);
            writer.WriteNode(reader, true);
            writer.Flush();
            //compression.Flush();
            buffer.Flush();

            ArraySegment<byte> cacheEntry = new ArraySegment<byte>(buffer.GetBuffer(), 0, (int)buffer.Length);

            cache.Insert(key,
                      cacheEntry,
                      null,
                      Cache.NoAbsoluteExpiration,
                      slidingExpiration);

            return CreateReaderFromArraySegment(cacheEntry);
        }

        public static XmlDictionaryReader AddFeed(this Cache cache, string key, SyndicationFeedFormatter<SyndicationFeed> reader)
        {
            return AddFeed(cache, "feed:"+key, reader, key, TimeSpan.FromMinutes(60), CacheItemPriority.Normal);
        }

        public static XmlDictionaryReader AddFeed(this Cache cache, string key, SyndicationFeedFormatter<SyndicationFeed> reader, CacheItemPriority priority)
        {
            return AddFeed(cache, "feed:"+key, reader, key, TimeSpan.FromMinutes(60), priority);
        }

        public static XmlDictionaryReader AddFeed(this Cache cache, string key, SyndicationFeedFormatter<SyndicationFeed> reader, TimeSpan slidingExpiration, CacheItemPriority priority)
        {
            return AddFeed(cache, "feed:" + key, reader, key, slidingExpiration, priority);
        }

        private static XmlDictionaryReader AddFeed(this Cache cache, string key, SyndicationFeedFormatter<SyndicationFeed> reader, string dependencyKey, TimeSpan slidingExpiration, CacheItemPriority priority)
        {
            MemoryStream buffer = new MemoryStream();
            //DeflateStream compression = new DeflateStream(buffer, CompressionMode.Compress);
            XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(buffer);
            reader.WriteTo(writer);
            writer.Flush();
            //compression.Flush();
            buffer.Flush();

            ArraySegment<byte> cacheEntry = new ArraySegment<byte>(buffer.GetBuffer(), 0, (int)buffer.Length);

            cache.Insert(key,
                      cacheEntry,
                      null,
                      Cache.NoAbsoluteExpiration,
                      slidingExpiration);

            return CreateReaderFromArraySegment(cacheEntry);
        }

        public static XmlDictionaryReader GetReader(this Cache cache, string key)
        {
            object cacheEntry = cache.Get(key);
            if (cacheEntry != null)
            {
                return CreateReaderFromArraySegment((ArraySegment<byte>)cacheEntry);
            }
            else
            {
                return null;
            }
        }

        private static XmlDictionaryReader CreateReaderFromArraySegment(ArraySegment<byte> cacheEntry)
        {
            XmlDictionaryReaderQuotas quotas = new XmlDictionaryReaderQuotas();
            MemoryStream buffer = new MemoryStream(cacheEntry.Array, cacheEntry.Offset, cacheEntry.Count);
            //DeflateStream decompression = new DeflateStream(buffer, CompressionMode.Decompress);
            XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(buffer, quotas);
            reader.MoveToContent();
            return reader;
        }


        public static void RemoveByKeyPrefix(this Cache cache, string key)
        {
            List<string> keysToRemove = new List<string>();
            foreach (DictionaryEntry e in cache)
            {
                if (((string)e.Key).StartsWith(key))
                {
                    keysToRemove.Add((string)e.Key);
                }
            }
            foreach (string keyToRemove in keysToRemove)
            {
                cache.Remove(keyToRemove);
            }
        }

        public static string MakeQueryKey(Moniker moniker, QueryDescription query, SerializationMode mode)
        {
            StringBuilder sb = new StringBuilder();
            if (query != null)
            {
                sb.Append(moniker.ToString()).Append("$").Append(mode.ToString()).Append("$").Append(query.ToString());
            }
            else
            {
                sb.Append(moniker.ToString()).Append("$").Append(mode.ToString());
            }
            return sb.ToString();
        }

        public static string MakeAggregateKey(Moniker moniker, string propertyName, SerializationMode mode)
        {
            StringBuilder sb = new StringBuilder();
            if (propertyName != null)
            {
                sb.Append(moniker.ToString()).Append("$").Append(mode.ToString()).Append("$").Append(propertyName);
            }
            else
            {
                sb.Append(moniker.ToString()).Append("$").Append(mode.ToString());
            }
            return sb.ToString();
        }

    }
}
